package com.mrfechetto.utils;

import java.lang.reflect.Method;

import org.apache.log4j.Logger;

public class ThreadDelegate
{
   private Method run;
   private Method error;
   private Method finish;
   private Object[] args;
   private String threadName;
   private Object delegate;
   
   public Logger getLogger(String methodName)
   {
      return Logger.getLogger(this.getClass().getName() + "." + methodName);
   }
   
   public ThreadDelegate(Object delegate, String methodName, final Object... args)
   {
      this.delegate = delegate;
      this.args = args;
      
      try
      {
         for(Method method : delegate.getClass().getMethods())
         {
            if(method.getName().equals(methodName))
            {
               run = method;
               break;
            }
         }
      }
      catch(Exception e)
      {
         getLogger("ThreadDelegate").error("exception attempting to create delegate, method with specified parameters was not found or is not accessible", e);
      }
      threadName = "PI." + delegate.getClass().getSimpleName() + "." + methodName;
   }
   
   public void start()
   {
      new Thread(new Runnable()
      {
         public void run()
         {
            try
            {
               run.invoke(delegate, args);
            }
            catch(Exception e)
            {
               if(error == null)
               {
                  getLogger("run").error("error occurred and no error method was specified", e);
               }
               else
               {
                  try
                  {
                     error.invoke(this, e);
                  }
                  catch(Exception e1)
                  {
                     getLogger("run").error("error occurred and error delegate was not implemented properly", e);
                  }
               }
            }
         }
      }, threadName).start();
      
      if(finish != null)
      {
         try
         {
            finish.invoke(this);
         }
         catch(Exception e)
         {
            getLogger("run").error("error occurred invoking finish method", e);
         }
      }

   }
   
   public static void start(Object delegate, String methodName, Object... args)
   {
      new ThreadDelegate(delegate, methodName, args).start();
   }
   
   public void setErrorDelegate(final Object delegate, String methodName)
   {
      try
      {
         error = delegate.getClass().getMethod(methodName, new Class<?>[]{ Throwable.class });
      }
      catch(Exception e)
      {
         getLogger("setErrorDelegate").error("exception attempting to create delegate, method with specified parameters was not found or is not accessible", e);
      }
   }

   public void setFinishDelegate(final Object delegate, String methodName) throws SecurityException, NoSuchMethodException
   {
      try
      {
         finish = delegate.getClass().getMethod(methodName, new Class<?>[]{});
      }
      catch(Exception e)
      {
         getLogger("setFinishDelegate").error("exception attempting to create delegate, method with specified parameters was not found or is not accessible", e);
      }
   }
}
